package com.lrkj.common.component.minio;

import cn.hutool.json.JSONObject;
import com.lrkj.common.exception.BaseException;
import com.lrkj.common.utils.DateUtils;
import com.lrkj.common.utils.StringUtils;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * minio的组件
 */
@Component
public class MinioComponent {

    private final static Logger log = LoggerFactory.getLogger(MinioComponent.class);

    private final MinioProperty minioProperty;

    public MinioComponent(MinioProperty minioProperty) {
        this.minioProperty = minioProperty;
    }

    private MinioClient minioClient;

    @PostConstruct
    private void initMinioClient() {
        try {
            minioClient = MinioClient.builder().endpoint(minioProperty.getUrl())
                    .credentials(minioProperty.getAccount(), minioProperty.getSecret()).build();

            log.info("Minio客户端初始化成功");

            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperty.getBucketName()).build())) {
                //初始化bucket
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperty.getBucketName()).build());
                log.info("存储桶[{}]初始化", minioProperty.getBucketName());
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("Minio客户端初始化失败:[{}]", e.getMessage());
        }
    }


    /**
     * 上传文件
     *
     * @param file 文件
     * @return 下载地址
     */
    public String uploadByFile(File file) {
        try {
            InputStream fileInputStream = new FileInputStream(file);
            return baseUpload(fileInputStream, file.getName());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件转换数据流失败:[{}]", e.getMessage());
            throw new BaseException(e.getMessage());
        }


    }


    /**
     * 上传文件
     *
     * @param file 文件
     * @return 下载地址
     */
    public String uploadByFile(MultipartFile file) {
        try {
            InputStream fileInputStream = file.getInputStream();
            return baseUpload(fileInputStream, file.getOriginalFilename());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件转换数据流失败:[{}]", e.getMessage());
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 上传文件
     *
     * @param file 文件
     * @return 下载地址
     */
    public String uploadByFile(MultipartFile file, String filePath) {
        try {
            InputStream fileInputStream = file.getInputStream();
            return baseUpload(fileInputStream, file.getOriginalFilename(), filePath);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件转换数据流失败:[{}]", e.getMessage());
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 上传文件
     *
     * @param file 文件
     * @return 下载地址
     */
    public String uploadByFile(File file, String filePath) {
        try {
            InputStream fileInputStream = new FileInputStream(file);
            return baseUpload(fileInputStream, file.getName(), filePath);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件转换数据流失败:[{}]", e.getMessage());
            throw new BaseException(e.getMessage());
        }


    }

    /**
     * 基础上传
     *
     * @param is       流
     * @param fileName 文件名称
     * @return 结果
     */
    private String baseUpload(InputStream is, String fileName) {
        try {
            //获取文件的后缀名 .jpg
            String filePath = DateUtils.datePath() + "/" + fileName;
            //String objectId = UUID.randomUUID().toString().replaceAll("-", "") + "/" + fileName;
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(minioProperty.getBucketName())
                    .object(filePath)
                    .stream(is, is.available(), -1)
                    .build());
            String viewUrl = minioProperty.getBucketName() + "/" + filePath;
            return viewUrl;
        } catch (Exception e) {
            e.printStackTrace();


            log.error("上传文件异常:[{}]", e.getMessage());
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 基础上传
     *
     * @param is       流
     * @param fileName 文件名称
     * @return 结果
     */
    private String baseUpload(InputStream is, String fileName, String filePath) {
        try {
            //获取文件的后缀名 .jpg
            if (StringUtils.isNotEmpty(filePath)) {
                filePath = filePath + "/" + fileName;
            } else {
                filePath = DateUtils.datePath() + "/" + fileName;
            }
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(minioProperty.getBucketName())
                    .object(filePath)
                    .stream(is, is.available(), -1)
                    .build());
            String viewUrl = minioProperty.getBucketName() + "/" + filePath;
            is.close();
            return viewUrl;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传文件异常:[{}]", e.getMessage());
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 获取后缀名称
     *
     * @param name 文件名称
     * @return 返回
     */
    private String getExtendName(String name) {
        String extentName = "";
        if (name.contains(".")) {
            extentName = name.substring(name.lastIndexOf("."));
        }
        return extentName;
    }

    /**
     * 获取文件流
     *
     * @param fileName 文件名
     * @return
     */
    public InputStream getObject(String fileName) {
        InputStream object = null;
        try {
            if (StringUtils.isNotEmpty(fileName)) {
                String bucketName = minioProperty.getBucketName() + "/";
                if (fileName.indexOf(bucketName) != -1) {
                    fileName = fileName.replace(bucketName, "");
                }
                object = minioClient
                        .getObject(GetObjectArgs.builder().bucket(minioProperty.getBucketName()).object(fileName).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("下载文件异常:[{}]", e.getMessage());
            throw new BaseException(e.getMessage());
        }
        return object;
    }


    /**
     * 删除
     *
     * @param fileName
     * @return
     * @throws Exception
     */
    public boolean removeMinio(String fileName) {
        try {
            if (StringUtils.isNotEmpty(fileName)) {
                fileName = fileName.replace("profile/", "");
            }
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioProperty.getBucketName()).object(fileName).build());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 判断文件是否存在
     *
     * @param fileName   文件名
     * @param bucketName 桶名（文件夹）
     * @return
     */
    public boolean isFileExisted(String fileName, String bucketName) {
        InputStream inputStream = null;
        try {
            inputStream = minioClient.getObject(bucketName, fileName);
            if (inputStream != null) {
                return true;
            }
        } catch (Exception e) {
            return false;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 删除文件
     *
     * @param bucketName 桶名（文件夹）
     * @param fileName   文件名
     * @return
     */
    public boolean delete(String bucketName, String fileName) {
        try {
            minioClient.removeObject(bucketName, fileName);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }


    /**
     * @param bucketName:
     * @author yanghui
     * @description: 创建桶
     * @date 2021/7/20 13:51
     */
    public void createBucketName(String bucketName) {
        try {
            if (StringUtils.isBlank(bucketName)) {
                return;
            }
            boolean isExist = minioClient.bucketExists(bucketName);
            if (isExist) {
                log.info("Bucket {} already exists.", bucketName);
            } else {
                minioClient.makeBucket(bucketName);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }

    /**
     * @param bucketName:
     * @author yanghui
     * @description: 删除桶
     * @date 2021/7/20 13:51
     */
    public void deleteBucketName(String bucketName) {
        try {
            if (StringUtils.isBlank(bucketName)) {
                return;
            }
            boolean isExist = minioClient.bucketExists(bucketName);
            if (isExist) {
                minioClient.removeBucket(bucketName);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }

    /**
     * @param bucketName:
     * @author yanghui
     * @description: 删除桶下面所有文件
     * @date 2021/7/20 13:51
     */
    public void deleteBucketFile(String bucketName) {
        try {
            if (StringUtils.isBlank(bucketName)) {
                return;
            }
            boolean isExist = minioClient.bucketExists(bucketName);
            if (isExist) {
                minioClient.deleteBucketLifeCycle(bucketName);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }


    public List<MinioFileVo> getFileList() throws Exception {
        DecimalFormat df = new DecimalFormat("0.00");
        List<Bucket> buckets = minioClient.listBuckets();
        List<MinioFileVo> list = new ArrayList<>(32);
        if (!buckets.isEmpty()) {
            buckets.forEach(s -> {
                try {
                    // 得到bucket下的文件
                    Iterable<Result<Item>> results = minioClient.listObjects(s.name());
                    // 循环遍历获取每一个文件对象
                    results.forEach(g -> {
                        try {
                            MinioFileVo fileVo = new MinioFileVo();
                            fileVo.setBucketName(s.name());  // 文件夹名称
                            fileVo.setFileName(URLDecoder.decode(g.get().objectName(), "utf-8"));  // 文件名称
                            Long size = g.get().size();
                            if (size > (1024 * 1024)) {
                                fileVo.setFileSize(df.format(((double) size / 1024 / 1024)) + "MB");  // 文件大小，如果超过1M，则把单位换成MB
                            } else if (size > 1024) {
                                fileVo.setFileSize(df.format(((double) size / 1024)) + "KB"); // 文件大小，如果没超过1M但是超过1000字节，则把单位换成KB
                            } else {
                                fileVo.setFileSize(size + "bytes");  // // 文件大小，如果没超过1000字节，则把单位换成bytes
                            }
                            list.add(fileVo);
                        } catch (ErrorResponseException e) {
                            e.printStackTrace();
                        } catch (InsufficientDataException e) {
                            e.printStackTrace();
                        } catch (InternalException e) {
                            e.printStackTrace();
                        } catch (InvalidBucketNameException e) {
                            e.printStackTrace();
                        } catch (InvalidKeyException e) {
                            e.printStackTrace();
                        } catch (InvalidResponseException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (NoSuchAlgorithmException e) {
                            e.printStackTrace();
                        } catch (XmlParserException e) {
                            e.printStackTrace();
                        } catch (ServerException e) {
                            e.printStackTrace();
                        }
                    });
                } catch (XmlParserException e) {
                    e.printStackTrace();
                }
            });
        }
        return list;
    }


}
